// **************************************************************
// COPYRIGHT(c)2020, Xidian University
// All rights reserved.
//
// IP LIB INDEX : 
// IP Name      : 
//                
// File name    :
// Module name  : 
// Full name    :
//
// Author       :  Hbing 
// Email        :  2629029232@qq.com
// Data         :  2020/8/24
// Version      :  V 1.0 
// 
//Abstract      :
// Called by    :  Father Module
// 
// Modification history
// ------------------------------------------------------------------------------------------------------
// 
//  
// *********************************************************************
`include "top_define.v"
// *******************
// TIMESCALE
// ******************* 
`timescale 1ns/1ps 

// *******************
// DESCRIPTION
// *******************
// 暂定总BD数量为4096个--12bit位宽--2Mbit
// 入队缓存申请，出队缓存释放，更新共享缓存区已使用BD数
//*******************
//DEFINE(s)
//*******************
//`define UDLY 1    //Unit delay, for non-blocking assignments in sequential logic

//*******************
//DEFINE MODULE PORT
module mem_management(
	//sysrem input/output
	input  wire 		clk  ,
	input  wire 		rst_n,
    input  wire  [9:0]  ram_2p_cfg_register,
	//with schedule_enqueue
	output reg  [ 31:0] BD_public_used               ,
	output reg 			mem_management_init_done     ,
	(*mark_debug = "true"*) input  wire 		mem_allocate_request         ,
	(*mark_debug = "true"*) output wire [ 15:0] mem_allocate_address         ,
	output wire   		mem_free_BD_fifo_empty       ,
	(*mark_debug = "true"*) input  wire [  5:0]	enqueue_Linked_list_ram_wren ,
	(*mark_debug = "true"*) input  wire [ 11:0] enqueue_Linked_list_ram_waddr,
	(*mark_debug = "true"*) input  wire [ 47:0] enqueue_Linked_list_ram_wdata,
	// output wire [ 39:0] enqueue_Linked_list_ram_rdata    ,
	(*mark_debug = "true"*) input  wire 		enqueue_BD_public_used_update_en ,
	(*mark_debug = "true"*) input  wire [ 31:0] enqueue_BD_public_used_update_num,
	//with schedule_dequeue
	(*mark_debug = "true"*) input  wire 		dequeue_BD_public_used_update_en ,
	(*mark_debug = "true"*) input  wire [ 31:0] dequeue_BD_public_used_update_num,
	//with mem_management_query
	(*mark_debug = "true"*) input  wire [ 11:0] dequeue_Linked_list_ram_raddr,
	(*mark_debug = "true"*) output wire [ 47:0] dequeue_Linked_list_ram_rdata,
	//with release_addr_fifo
	(*mark_debug = "true"*) input  wire  		release_addr_fifo_empty,
	(*mark_debug = "true"*) output reg  		release_addr_fifo_rden ,
	(*mark_debug = "true"*) input  wire [ 17:0] release_addr_fifo_rdata,   //fisrt_BD+last_BD+BD_addr
	//cpu_interface
	(*mark_debug = "true"*) output reg  [ 31:0] ro_reg_np_freeblocknumber_register
	);

//*******************
//DEFINE PARAMETER
//*******************
//Parameter(s) 
localparam IDLE                   = 4'b0000;
localparam READ_RELEASE_ADDR_FIFO = 4'b0001;
localparam WRITE_FREE_FIFO        = 4'b0010;

//Linked_list_ram--字节写入，扩充为8的整数倍
// _ _ _1_ _ _ _ _ _1_ _ _ _ _ _ _ 6 _ _ _  _ _ _ 12 _ _ _ _ _ _ 11 _ _ _
//|    39     |    38     |      37~32     |     31~16    |     15~0     |
//|__first_BD_|__last_BD__|__valid_length__|__BD_address__|_frame_length_|
//*********************
//INNER SIGNAL DECLARATION
//*********************
//REGS
//状态机
(*mark_debug = "true"*) reg [3:0] c_state,n_state;
//初始化计数信号
reg [15:0] init_cnt;
//写free_BD_fifo信号
reg        free_BD_fifo_wren ;
reg [15:0] free_BD_fifo_wdata;
reg [17:0] release_addr_fifo_rdata_reg;
reg 	   release_addr_fifo_empty_reg;
//WIRES
//释放的BD地址
wire        release_fisrt_BD;
wire        release_last_BD ;
wire [15:0] release_BD_addr ;
//free_BD_fifo满信号
wire free_BD_fifo_full;
//*********************
//INSTANTCE MODULE
//*********************
//空闲BD地址FIFO
`ifdef ASIC
FIFO_w16_d4096_fwft U_free_BD_fifo_asic(
    .clk(clk),
    .clr(rst_n),
    .ram_2p_cfg_register(ram_2p_cfg_register),                      
    .w_data(free_BD_fifo_wdata),
    .w_we(free_BD_fifo_wren),
    .w_full(free_BD_fifo_full),
    .w_afull(),
                          
    .r_data(mem_allocate_address),
    .r_re(mem_allocate_request),
    .r_empty(mem_free_BD_fifo_empty),
    .r_aempty()	
);
ram_2p_d4096_w48_wrapper U_Linked_list_ram_asic(
.clk(clk),
.ram_2p_cfg_register(ram_2p_cfg_register),
.wren(enqueue_Linked_list_ram_wren),
.waddr(enqueue_Linked_list_ram_waddr),
.wdata(enqueue_Linked_list_ram_wdata),
.rden(6'b111111),
.raddr(dequeue_Linked_list_ram_raddr),
.rdata(dequeue_Linked_list_ram_rdata)	
);
`else
FIFO_w16_d8192 U_free_BD_fifo(
    .clk                  (clk                    ), // input clk
    .rst                  (~rst_n                 ), // input rst
    .din                  (free_BD_fifo_wdata     ), // input [15 : 0] din
    .wr_en                (free_BD_fifo_wren      ), // input wr_en
    .rd_en                (mem_allocate_request   ), // input rd_en
    .dout                 (mem_allocate_address   ), // output [15 : 0] dout
    .full                 (free_BD_fifo_full      ), // output full
    .empty                (mem_free_BD_fifo_empty )
    // output empty);
	);
//BD信息链表RAM
Linked_list_ram_w40_d8192 U_Linked_list_ram(
    .clka                 (clk                               ), // input clka
    .wea                  (enqueue_Linked_list_ram_wren      ), // input [4 : 0] wea
    .addra                (enqueue_Linked_list_ram_waddr     ), // input [11 : 0] addra
    .dina                 (enqueue_Linked_list_ram_wdata     ), // input [39 : 0] dina
    // .douta                (                                  ), // output [39 : 0] douta
    .clkb                 (clk                               ), // input clkb
    // .web                  (5'd0                              ), // input [4 : 0] web
    .addrb                (dequeue_Linked_list_ram_raddr     ), // input [11 : 0] addrb
    // .dinb                 (40'd0                             ), // input [39 : 0] dinb
    .doutb                (dequeue_Linked_list_ram_rdata     )
    // output [39 : 0] doutb
	);
`endif
//*********************
//MAIN CORE
//*********************
assign release_fisrt_BD = release_addr_fifo_rdata_reg[17];
assign release_last_BD  = release_addr_fifo_rdata_reg[16];
assign release_BD_addr  = release_addr_fifo_rdata_reg[15:0];
//打拍采样
always @(posedge clk) begin
	release_addr_fifo_rdata_reg <= release_addr_fifo_rdata; 
	release_addr_fifo_empty_reg <= release_addr_fifo_empty;
end

//三段式状态机
always @(posedge clk or negedge rst_n) begin
	if (~rst_n) begin
		c_state <= IDLE;
	end
	else begin
		c_state <= n_state;
	end
end

always @(*) begin
	case(c_state)
		IDLE:
		begin
			if ((release_addr_fifo_empty == 1'b0) && (release_addr_fifo_empty_reg == 1'b0)) begin
				n_state = READ_RELEASE_ADDR_FIFO;
			end
			else begin
				n_state = IDLE;
			end
		end
		READ_RELEASE_ADDR_FIFO:
		begin
			n_state = WRITE_FREE_FIFO;
		end
		WRITE_FREE_FIFO:
		begin
			// if ((release_addr_fifo_empty == 1'b0)) begin
			// 	n_state = READ_RELEASE_ADDR_FIFO;
			// end
			// else begin
				n_state = IDLE;
			// end
		end
		default:
		begin
			n_state = IDLE;
		end
	endcase
end

//初始化计数--空闲BD地址--从1开始--0为无效BD
always @(posedge clk or negedge rst_n) begin
	if (~rst_n) begin
		init_cnt <= 16'd1;
	end
	else if ((free_BD_fifo_full == 1'b0) && (mem_management_init_done == 1'b0)) begin
		init_cnt <= init_cnt + 1'b1;
	end
	else begin
		init_cnt <= 16'd1;
	end
end

//缓存管理初始化完毕--写入free_BD_fifo完成
always @(posedge clk or negedge rst_n) begin
	if (~rst_n) begin
		mem_management_init_done <= 1'b0;
	end
	else if (init_cnt == `BDNUM) begin
		mem_management_init_done <= 1'b1;
	end
	else begin
		mem_management_init_done <= mem_management_init_done;
	end
end

//写free_BD_fifo
always @(posedge clk or negedge rst_n) begin
	if (~rst_n) begin
		free_BD_fifo_wren  <= 1'b0;
		free_BD_fifo_wdata <= 16'd0;
	end
	else if (free_BD_fifo_full == 1'b0 && mem_management_init_done == 1'b0) begin  //初始化写入空闲BD地址
		free_BD_fifo_wren  <= 1'b1;
		free_BD_fifo_wdata <= init_cnt;
	end
	else if (c_state == WRITE_FREE_FIFO) begin  //出队释放BD地址
		free_BD_fifo_wren  <= 1'b1;
		free_BD_fifo_wdata <= release_BD_addr;
	end
	else begin
		free_BD_fifo_wren  <= 1'b0;
		free_BD_fifo_wdata <= 16'd0;
	end
end

//拉高释放地址FIFO读使能
always @(posedge clk or negedge rst_n) begin
	if (~rst_n) begin
		release_addr_fifo_rden <= 1'b0;
	end
	else if (n_state == READ_RELEASE_ADDR_FIFO) begin
		release_addr_fifo_rden <= 1'b1;
	end
	else begin
		release_addr_fifo_rden <= 1'b0;
	end
end

//更新共享缓存区已使用BD数
always @(posedge clk or negedge rst_n) begin
	if (~rst_n) begin
		BD_public_used <= 32'd0;
	end
	else if ((enqueue_BD_public_used_update_en == 1'b1) && (dequeue_BD_public_used_update_en == 1'b1)) begin
		BD_public_used <= BD_public_used + enqueue_BD_public_used_update_num - dequeue_BD_public_used_update_num;
	end
	else if (enqueue_BD_public_used_update_en == 1'b1) begin
		BD_public_used <= BD_public_used + enqueue_BD_public_used_update_num;
	end
	else if (dequeue_BD_public_used_update_en == 1'b1) begin
		BD_public_used <= BD_public_used - dequeue_BD_public_used_update_num;
	end
	else begin
		BD_public_used <= BD_public_used;
	end
end

//缓存剩余情况-----cpu接口
always @(posedge clk or negedge rst_n) begin : ro_reg_np_freeblocknumber_register_update
	if (~rst_n) begin
		// reset
		ro_reg_np_freeblocknumber_register <= 32'b0;
	end
	else if (free_BD_fifo_wren & mem_allocate_request) begin
		ro_reg_np_freeblocknumber_register <= ro_reg_np_freeblocknumber_register;
	end
	else if (free_BD_fifo_wren) begin
		ro_reg_np_freeblocknumber_register <= ro_reg_np_freeblocknumber_register + 32'b1;
	end
	else if (mem_allocate_request) begin
		ro_reg_np_freeblocknumber_register <= ro_reg_np_freeblocknumber_register - 32'b1;
	end
	else begin
		ro_reg_np_freeblocknumber_register <= ro_reg_np_freeblocknumber_register;
	end
end

endmodule
